package com.github.butid.data.codec;

import cn.hutool.core.util.IdUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 报文消息解析器
 * @author wangjing.dc@qq.com
 * @since 2020/8/4
 */
@Slf4j
@Component
public class XmlToCmdMessageDecoder extends MessageToMessageDecoder<String> {


    @Override
    protected void decode(ChannelHandlerContext ctx, String msg, List<Object> out) throws Exception {
        CmdMessage cmd = new CmdMessage();
        Header header = new Header();
        Map<String, Object> body = new HashMap<>();
        cmd.setHeader(header).setBody(body);

        SAXReader saxReader = new SAXReader();
        Document doc = saxReader.read(new ByteArrayInputStream(msg.getBytes("utf-8")));
        doc.getRootElement().elements().forEach((item) -> {
             switch (item.getName()){
                 case "TRNTYPE": header.setCmdType(item.getStringValue()); break;
                 case "TRNCODE": header.setCmdCode(item.getStringValue()); break;
                 case "DEVID": header.setTermId(item.getStringValue()); break;
                 case "CTIME": header.setDateImte(item.getStringValue()); break;
                 case "TRNEJ": header.setClientSeq(item.getStringValue()); break;
                 default: body.put(item.getName(), parseBody(item));
             }
        });

        // 添加唯一请求id
        header.setServerSeq(IdUtil.fastSimpleUUID());
        out.add(cmd);
    }

    /**
     * 解析消息体
     * @param element
     * @return
     */
    private Object parseBody(Element element) {
        if(element.content() == null || element.content().size() <= 0) return "";
        if(isTextNode(element)) return element.getStringValue();

        Map<String, Object> ret = new HashMap<>();
        element.elements().forEach((item) -> {
            if(isTextNode(element)){
                ret.put(item.getName(), item.getStringValue());
            }else{
                ret.put(item.getName(), this.parseBody(item));
            }
        });

        return ret;
    }

    /**
     * element节点是否text节点，比如：<cmdseq>sssssdfeefdfd</cmdseq>
     * @param element
     * @return
     */
    private boolean isTextNode(Element element) {
        return element.nodeCount() == 1 && element.node(0).getNodeType() == Node.TEXT_NODE;
    }
}
